package com.manager.commons.utils;

//                   _ooOoo_    
//                  o8888888o    
//                  88" . "88    
//                  (| -_- |)    
//                   O\ = /O    
//               ____/'---'\____    
//              /. '\\| : |//' .\    
//             // \\||| : |||// \\   
//            // _|||||-:-|||||_ \\    
//           // | | \\\ - /// | | \\
//           || |_| ''\---/'' |_| || 
//            \ .-\___/'-'\___/-. /    
//          ___\. .' /--.--\ '. ./___    
//        .""'< `.___\_<|>_/___.' >'"".    
//       | |: `- \`.|'\ _ /'|.`/ -` :| |    
//        \ \ `-. \_ __\ /__ _/ .-` / /    
//======'-.___`-.___\_______/___.-`___.-'======    
//                   '=---='    
//.................................................    
//写一哈代码，你就青叫唤；信龟儿设计，你逗是傻逼。
//永无Bug，啷个可能！求佛主保佑也没球用！

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Random;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

/**
 * QRUtils(二维码)
 * @author H
 * @version V1.0
 */
public class QRUtils {

	private static final String CHARSET = "UTF-8";
	/**
	 * 格式
	 */
	private static final String FORMAT_NAME = "PNG";
	/**
	 * 二维码尺寸
	 */
	private static int QR_SIZE = 300;
	/**
	 * 二维码宽度
	 */
	private static final int QR_LOGO_WIDTH = 120;
	/**
	 * 二维码高度
	 */
	private static final int QR_LOGO_HEIGHT = 120;
	/**
	 * 默认是黑色
	 */
	private static final int QR_COLOR = 0xFF000000;
	/**
	 * 背景颜色
	 */
	private static final int QR_BG_COLOR = 0xFFFFFFFF;

	private static final Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>() {
		private static final long serialVersionUID = -4235652933039905906L;
		{
			put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);// 设置QR二维码的纠错级别（H为最高级别）具体级别信息
			put(EncodeHintType.CHARACTER_SET, CHARSET);// 设置编码方式
			put(EncodeHintType.MARGIN, 0);
		}
	};

	/**
	 * 插入图片
	 * @param source
	 * @param imgPath
	 * @param imgCompress
	 * @throws Exception
	 */
	private static void insertImage(BufferedImage source, String imgPath, boolean imgCompress) throws Exception {
		File file = new File(imgPath);
		if (!file.exists()) {
			throw new Exception(imgPath + "  该文件不存在！");
		}
		Image src = ImageIO.read(new File(imgPath));
		int width = src.getWidth(null);
		int height = src.getHeight(null);
		// 压缩图片
		if (imgCompress) {
			if (width > QR_LOGO_WIDTH) {
				width = QR_LOGO_WIDTH;
			}
			if (height > QR_LOGO_HEIGHT) {
				height = QR_LOGO_HEIGHT;
			}
			Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
			BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
			Graphics g = tag.getGraphics();
			g.drawImage(image, 0, 0, null); // 绘制缩小后的图
			g.dispose();
			tag.flush();
			src = image;
		}
		// 插入图片
		Graphics2D graph = source.createGraphics();
		int x = (QR_SIZE - width) / 2;
		int y = (QR_SIZE - height) / 2;
		graph.drawImage(src, x, y, width, height, null);
		graph.setStroke(new BasicStroke(3f));
		graph.draw(new RoundRectangle2D.Float(x, y, width, width, 6, 6));
		graph.dispose();
		src.flush();
	}

	/**
	 * 插入文字
	 * @param text
	 * @param height
	 * @param image
	 * @return
	 */
	private static BufferedImage insertText(BufferedImage source, String text, int height) {
		BufferedImage outImage = new BufferedImage(QR_SIZE, QR_SIZE + 45, BufferedImage.TYPE_4BYTE_ABGR);
		Graphics2D outg = outImage.createGraphics();
		outg.drawImage(source, 0, 0, source.getWidth(), source.getHeight(), null);
		outg.setColor(Color.BLACK);
		outg.setFont(new Font("楷体", Font.BOLD, 30)); // 字体、字型、字号
		int strWidth = outg.getFontMetrics().stringWidth(text);
		if (strWidth > (QR_SIZE - 1)) {
			// 长度过长就截取前面部分,长度过长就换行
			String note1 = text.substring(0, text.length() / 2);
			String note2 = text.substring(text.length() / 2);
			int strWidth1 = outg.getFontMetrics().stringWidth(note1);
			int strWidth2 = outg.getFontMetrics().stringWidth(note2);
			outg.drawString(note1, 200 - strWidth1 / 2, height + (outImage.getHeight() - height) / 2 + 12);
			BufferedImage outImage2 = new BufferedImage(400, 485, BufferedImage.TYPE_4BYTE_ABGR);
			Graphics2D outg2 = outImage2.createGraphics();
			outg2.drawImage(outImage, 0, 0, outImage.getWidth(), outImage.getHeight(), null);
			outg2.setColor(Color.BLACK);
			outg2.setFont(new Font("宋体", Font.BOLD, 30)); // 字体、字型、字号
			outg2.drawString(note2, (QR_SIZE / 2) - strWidth2 / 2, outImage.getHeight() + (outImage2.getHeight() - outImage.getHeight()) / 2 + 5);
			outg2.dispose();
			outImage2.flush();
			outImage = outImage2;
		} else {
			outg.drawString(text, (QR_SIZE / 2) - strWidth / 2, height + (outImage.getHeight() - height) / 2 + 12); // 画文字
		}
		outg.dispose();
		outImage.flush();
		return outImage;
	}

	/**
	 * 生成图片
	 * @param size
	 * @param content
	 * @param text
	 * @param imgPath
	 * @param imgCompress
	 * @return
	 * @throws Exception
	 */
	public static BufferedImage createImage(int size, String content, String text, String imgPath, boolean imgCompress) throws Exception {
		hints.put(EncodeHintType.MARGIN, 1);
		if (size > 0) {
			QR_SIZE = size;
		}
		BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QR_SIZE, QR_SIZE, hints);
		int width = bitMatrix.getWidth();
		int height = bitMatrix.getHeight();
		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				image.setRGB(x, y, bitMatrix.get(x, y) ? QR_COLOR : QR_BG_COLOR);
			}
		}
		// 插入图片
		if (StringUtil.isNotEmpty(imgPath)) {
			insertImage(image, imgPath, imgCompress);
		}
		// 自定义文本描述
		if (StringUtil.isNotEmpty(text)) {
			image = insertText(image, text, height);
		}
		return image;
	}

	/**
	 * 生成图片
	 * @param content
	 * @param text
	 * @param imgPath
	 * @param imgCompress
	 * @return
	 * @throws Exception
	 */
	public static BufferedImage createImage(String content, String text, String imgPath, boolean imgCompress) throws Exception {
		return createImage(QR_SIZE, content, text, imgPath, imgCompress);
	}

	/**
	 * 创建文件目录
	 * @param destPath
	 */
	public static void mkdirs(String filePath) {
		File file = new File(filePath);
		// 当文件夹不存在时，mkdirs会自动创建多层目录，区别于mkdir．(mkdir如果父目录不存在则会抛出异常)
		if (!file.exists() && !file.isDirectory()) {
			file.mkdirs();
		}
	}

	/**
	 * 加密
	 * @param size
	 * @param content
	 * @param text
	 * @param imgPath
	 * @param imgCompress
	 * @param filePath
	 * @param fileName
	 * @throws Exception
	 */
	public static String encode(int size, String content, String text, String imgPath, boolean imgCompress, String filePath, String fileName) throws Exception {
		BufferedImage image = createImage(size, content, text, imgPath, imgCompress);
		mkdirs(filePath);
		if (StringUtil.isEmpty(fileName)) {
			fileName = String.valueOf(new Random().nextInt(99999999));
		}
		String path = filePath + "/" + fileName + ".png";
		ImageIO.write(image, FORMAT_NAME, new File(path));
		return path;
	}

	/**
	 * 加密
	 * @param content
	 * @param text
	 * @param imgPath
	 * @param imgCompress
	 * @param filePath
	 * @param fileName
	 * @throws Exception
	 */
	public static String encode(String content, String text, String imgPath, boolean imgCompress, String filePath, String fileName) throws Exception {
		return encode(-1, content, text, imgPath, imgCompress, filePath, fileName);
	}

	/**
	 * 加密
	 * @param content
	 * @param imgPath
	 * @param imgCompress
	 * @param filePath
	 * @throws Exception
	 */
	public static String encode(String content, String imgPath, boolean imgCompress, String filePath) throws Exception {
		return encode(content, "", imgPath, imgCompress, filePath, "");
	}

	/**
	 * 加密
	 * @param content
	 * @param text
	 * @param imgPath
	 * @param imgCompress
	 * @param filPath
	 * @throws Exception
	 */
	public static String encode(String content, String text, String imgPath, boolean imgCompress, String filePath) throws Exception {
		return encode(content, text, imgPath, imgCompress, filePath, "");
	}

	/**
	 * 加密
	 * @param content
	 * @param filePath
	 * @throws Exception
	 */
	public static String encode(String content, String filePath) throws Exception {
		return encode(content, "", "", false, filePath, "");
	}

	/**
	 * 加密
	 * @param content
	 * @param filePath
	 * @throws Exception
	 */
	public static String encode(String content, String text, String filePath) throws Exception {
		return encode(content, text, "", false, filePath, "");
	}

	/**
	 * 加密
	 * @param content
	 * @param filePath
	 * @throws Exception
	 */
	public static String encode(int size, String content, String text, String filePath, String fileName) throws Exception {
		return encode(size, content, text, "", false, filePath, fileName);
	}

	/**
	 * 加密
	 * @param content
	 * @param filePath
	 * @throws Exception
	 */
	public static String encode(String content, String text, String filePath, String fileName) throws Exception {
		return encode(content, text, "", false, filePath, fileName);
	}

	/**
	 * 加密
	 * @param content
	 * @param text
	 * @param imgPath
	 * @param imgCompress
	 * @param output
	 * @throws Exception
	 */
	public static void encode(String content, String text, String imgPath, boolean imgCompress, OutputStream output) throws Exception {
		BufferedImage image = createImage(content, text, imgPath, imgCompress);
		ImageIO.write(image, FORMAT_NAME, output);
	}

	/**
	 * 加密
	 * @param content
	 * @param output
	 * @throws Exception
	 */
	public static void encode(String content, OutputStream output) throws Exception {
		encode(content, "", "", false, output);
	}

	/**
	 * 解密
	 * @param file
	 * @return
	 * @throws Exception
	 */
	public static String decode(File file) throws Exception {
		BufferedImage image;
		image = ImageIO.read(file);
		if (image == null) {
			return null;
		}
		BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
		BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
		Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
		hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
		Result result = new MultiFormatReader().decode(bitmap, hints);
		String text = result.getText();
		return text;
	}

	/**
	 * 解密
	 * @param path
	 * @return
	 * @throws Exception
	 */
	public static String decode(String path) throws Exception {
		return decode(new File(path));
	}
}